﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Terraria.Localization;
using Terraria.ModLoader.IO;

namespace Terraria.ModLoader
{
	// Token: 0x020001E4 RID: 484
	public class ModNet
	{
		// Token: 0x1700017D RID: 381
		// (get) Token: 0x06001455 RID: 5205 RVA: 0x00010340 File Offset: 0x0000E540
		// (set) Token: 0x06001456 RID: 5206 RVA: 0x00010347 File Offset: 0x0000E547
		public static bool AllowVanillaClients { get; internal set; }

		// Token: 0x06001457 RID: 5207 RVA: 0x0001034F File Offset: 0x0000E54F
		public static bool IsModdedClient(int i)
		{
			return ModNet.isModdedClient[i];
		}

		// Token: 0x06001458 RID: 5208 RVA: 0x00010358 File Offset: 0x0000E558
		public static Mod GetMod(int netID)
		{
			if (netID < 0 || netID >= ModNet.netMods.Length)
			{
				return null;
			}
			return ModNet.netMods[netID];
		}

		// Token: 0x06001459 RID: 5209 RVA: 0x00412EF4 File Offset: 0x004110F4
		internal static void AssignNetIDs()
		{
			ModNet.netMods = (from mod in ModLoader.LoadedMods
			where mod.Side != ModSide.Server
			select mod).ToArray<Mod>();
			short num = 0;
			while ((int)num < ModNet.netMods.Length)
			{
				ModNet.netMods[(int)num].netID = num;
				num += 1;
			}
		}

		// Token: 0x0600145A RID: 5210 RVA: 0x00010371 File Offset: 0x0000E571
		internal static void Unload()
		{
			ModNet.netMods = null;
		}

		// Token: 0x0600145B RID: 5211 RVA: 0x00412F54 File Offset: 0x00411154
		internal static void SyncMods(int clientIndex)
		{
			ModPacket modPacket = new ModPacket(251, 256);
			modPacket.Write(ModNet.AllowVanillaClients);
			Mod[] array = (from mod in ModLoader.LoadedMods
			where mod.Side == ModSide.Both
			select mod).ToArray<Mod>();
			modPacket.Write(array.Length);
			foreach (Mod mod2 in array)
			{
				modPacket.Write(mod2.Name);
				modPacket.Write(mod2.Version.ToString());
				modPacket.Write(mod2.File.hash);
				modPacket.Write(mod2.File.ValidModBrowserSignature);
			}
			modPacket.Send(clientIndex, -1);
		}

		// Token: 0x0600145C RID: 5212 RVA: 0x00413014 File Offset: 0x00411214
		internal static void SyncClientMods(BinaryReader reader)
		{
			ModNet.AllowVanillaClients = reader.ReadBoolean();
			Main.statusText = Language.GetTextValue("tModLoader.MPSyncingMods");
			Mod[] loadedMods = ModLoader.LoadedMods;
			LocalMod[] source = ModLoader.FindMods();
			bool needsReload = false;
			ModNet.downloadQueue.Clear();
			HashSet<string> hashSet = new HashSet<string>();
			List<ModNet.ModHeader> list = new List<ModNet.ModHeader>();
			int num = reader.ReadInt32();
			int i = 0;
			while (i < num)
			{
				ModNet.ModHeader header = new ModNet.ModHeader(reader.ReadString(), new Version(reader.ReadString()), reader.ReadBytes(20), reader.ReadBoolean());
				hashSet.Add(header.name);
				Mod mod3 = loadedMods.SingleOrDefault((Mod m) => m.Name == header.name);
				if (mod3 != null)
				{
					if (!header.Matches(mod3.File))
					{
						header.path = mod3.File.path;
						goto IL_13E;
					}
				}
				else
				{
					LocalMod[] array = (from m in source
					where m.Name == header.name
					select m).ToArray<LocalMod>();
					LocalMod localMod = array.FirstOrDefault((LocalMod mod) => header.Matches(mod.modFile));
					if (localMod != null)
					{
						localMod.Enabled = true;
						needsReload = true;
					}
					else
					{
						if (array.Length != 0)
						{
							header.path = array[0].modFile.path;
							goto IL_13E;
						}
						goto IL_13E;
					}
				}
				IL_17B:
				i++;
				continue;
				IL_13E:
				if (ModNet.downloadModsFromServers && (header.signed || !ModNet.onlyDownloadSignedMods))
				{
					ModNet.downloadQueue.Enqueue(header);
					goto IL_17B;
				}
				list.Add(header);
				goto IL_17B;
			}
			foreach (Mod mod2 in loadedMods)
			{
				if (mod2.Side == ModSide.Both && !hashSet.Contains(mod2.Name))
				{
					ModLoader.DisableMod(mod2.Name);
					needsReload = true;
				}
			}
			if (list.Count > 0)
			{
				string text = Language.GetTextValue("tModLoader.MPServerModsCantDownload");
				text += (ModNet.downloadModsFromServers ? Language.GetTextValue("tModLoader.MPServerModsCantDownloadReasonSigned") : Language.GetTextValue("tModLoader.MPServerModsCantDownloadReasonAutomaticDownloadDisabled"));
				text = text + ".\n" + Language.GetTextValue("tModLoader.MPServerModsCantDownloadChangeSettingsHint") + "\n";
				foreach (ModNet.ModHeader arg in list)
				{
					text = text + "\n    " + arg;
				}
				ErrorLogger.LogMissingMods(text);
				return;
			}
			if (ModNet.downloadQueue.Count > 0)
			{
				ModNet.DownloadNextMod();
				return;
			}
			ModNet.OnModsDownloaded(needsReload);
		}

		// Token: 0x0600145D RID: 5213 RVA: 0x004132B8 File Offset: 0x004114B8
		private static void DownloadNextMod()
		{
			ModNet.downloadingMod = ModNet.downloadQueue.Dequeue();
			ModNet.downloadingFile = null;
			ModPacket modPacket = new ModPacket(252, 256);
			modPacket.Write(ModNet.downloadingMod.name);
			modPacket.Send(-1, -1);
		}

		// Token: 0x0600145E RID: 5214 RVA: 0x00413304 File Offset: 0x00411504
		internal static void SendMod(string modName, int toClient)
		{
			Mod mod = ModLoader.GetMod(modName);
			string path = mod.File.path;
			FileStream fileStream = new FileStream(path, FileMode.Open);
			ModPacket modPacket = new ModPacket(252, 256);
			modPacket.Write(mod.DisplayName);
			modPacket.Write(fileStream.Length);
			modPacket.Send(toClient, -1);
			byte[] array = new byte[16384];
			int count;
			while ((count = fileStream.Read(array, 0, array.Length)) > 0)
			{
				ModPacket modPacket2 = new ModPacket(252, 16387);
				modPacket2.Write(array, 0, count);
				modPacket2.Send(toClient, -1);
			}
			fileStream.Close();
		}

		// Token: 0x0600145F RID: 5215 RVA: 0x004133AC File Offset: 0x004115AC
		internal static void ReceiveMod(BinaryReader reader)
		{
			if (ModNet.downloadingMod == null)
			{
				return;
			}
			try
			{
				if (ModNet.downloadingFile == null)
				{
					Interface.downloadMod.SetDownloading(reader.ReadString());
					Interface.downloadMod.SetCancel(delegate
					{
						FileStream fileStream2 = ModNet.downloadingFile;
						if (fileStream2 != null)
						{
							fileStream2.Close();
						}
						ModNet.downloadingMod = null;
						Netplay.disconnect = true;
						Main.menuMode = 0;
					});
					Main.menuMode = 10009;
					ModNet.downloadingLength = reader.ReadInt64();
					ModNet.downloadingFile = new FileStream(ModNet.downloadingMod.path, FileMode.Create);
				}
				else
				{
					byte[] array = reader.ReadBytes((int)Math.Min(ModNet.downloadingLength - ModNet.downloadingFile.Position, 16384L));
					ModNet.downloadingFile.Write(array, 0, array.Length);
					Interface.downloadMod.SetProgress(ModNet.downloadingFile.Position, ModNet.downloadingLength);
					if (ModNet.downloadingFile.Position == ModNet.downloadingLength)
					{
						ModNet.downloadingFile.Close();
						TmodFile tmodFile = new TmodFile(ModNet.downloadingMod.path);
						tmodFile.Read(TmodFile.LoadedState.Info, null);
						if (!ModNet.downloadingMod.Matches(tmodFile))
						{
							throw new Exception(Language.GetTextValue("tModLoader.MPErrorModHashMismatch"));
						}
						if (ModNet.downloadingMod.signed && !tmodFile.ValidModBrowserSignature)
						{
							throw new Exception(Language.GetTextValue("tModLoader.MPErrorModNotSigned"));
						}
						ModLoader.EnableMod(tmodFile.name);
						if (ModNet.downloadQueue.Count > 0)
						{
							ModNet.DownloadNextMod();
						}
						else
						{
							ModNet.OnModsDownloaded(true);
						}
					}
				}
			}
			catch (Exception e)
			{
				try
				{
					FileStream fileStream = ModNet.downloadingFile;
					if (fileStream != null)
					{
						fileStream.Close();
					}
				}
				catch
				{
				}
				File.Delete(ModNet.downloadingMod.path);
				ErrorLogger.LogException(e, Language.GetTextValue("tModLoader.MPErrorModDownloadError", ModNet.downloadingMod.name));
				ModNet.downloadingMod = null;
			}
		}

		// Token: 0x06001460 RID: 5216 RVA: 0x00413598 File Offset: 0x00411798
		private static void OnModsDownloaded(bool needsReload)
		{
			if (needsReload)
			{
				ModLoader.PostLoad = new Action(ModNet.NetReload);
				ModLoader.Reload();
				return;
			}
			ModNet.downloadingMod = null;
			ModNet.netMods = null;
			foreach (Mod mod in ModLoader.LoadedMods)
			{
				mod.netID = -1;
			}
			new ModPacket(251, 256).Send(-1, -1);
		}

		// Token: 0x06001461 RID: 5217 RVA: 0x00413600 File Offset: 0x00411800
		private static void NetReload()
		{
			Main.ActivePlayerFileData = Player.GetFileData(Main.ActivePlayerFileData.Path, Main.ActivePlayerFileData.IsCloudSave);
			Main.ActivePlayerFileData.SetAsActive();
			Main.player[Main.myPlayer].hostile = false;
			Main.clientPlayer = (Player)Main.player[Main.myPlayer].clientClone();
			Main.menuMode = 10;
			ModNet.OnModsDownloaded(false);
		}

		// Token: 0x06001462 RID: 5218 RVA: 0x00413670 File Offset: 0x00411870
		internal static void SendNetIDs(int toClient)
		{
			ModPacket modPacket = new ModPacket(250, 256);
			modPacket.Write(-1);
			modPacket.Write(ModNet.netMods.Length);
			foreach (Mod mod in ModNet.netMods)
			{
				modPacket.Write(mod.Name);
			}
			ItemLoader.WriteNetGlobalOrder(modPacket);
			WorldHooks.WriteNetWorldOrder(modPacket);
			modPacket.Send(toClient, -1);
		}

		// Token: 0x06001463 RID: 5219 RVA: 0x004136DC File Offset: 0x004118DC
		private static void ReadNetIDs(BinaryReader reader)
		{
			Mod[] loadedMods = ModLoader.LoadedMods;
			List<Mod> list = new List<Mod>();
			int num = reader.ReadInt32();
			short num2 = 0;
			while ((int)num2 < num)
			{
				string name = reader.ReadString();
				Mod mod = loadedMods.SingleOrDefault((Mod m) => m.Name == name);
				list.Add(mod);
				if (mod != null)
				{
					mod.netID = num2;
				}
				num2 += 1;
			}
			ModNet.netMods = list.ToArray();
			ItemLoader.ReadNetGlobalOrder(reader);
			WorldHooks.ReadNetWorldOrder(reader);
		}

		// Token: 0x06001464 RID: 5220 RVA: 0x00413760 File Offset: 0x00411960
		internal static void HandleModPacket(BinaryReader reader, int whoAmI)
		{
			short num = reader.ReadInt16();
			if (num < 0)
			{
				ModNet.ReadNetIDs(reader);
				return;
			}
			Mod mod = ModNet.GetMod((int)num);
			if (mod == null)
			{
				return;
			}
			mod.HandlePacket(reader, whoAmI);
		}

		// Token: 0x06001465 RID: 5221 RVA: 0x00413794 File Offset: 0x00411994
		internal static bool HijackGetData(ref byte messageType, ref BinaryReader reader, int playerNumber)
		{
			if (ModNet.netMods == null)
			{
				return false;
			}
			bool flag = false;
			long position = reader.BaseStream.Position;
			long num = position;
			foreach (Mod mod in ModLoader.LoadedMods)
			{
				if (mod.HijackGetData(ref messageType, ref reader, playerNumber))
				{
					flag = true;
					num = Math.Max(reader.BaseStream.Position, num);
				}
				reader.BaseStream.Position = position;
			}
			if (flag)
			{
				reader.BaseStream.Position = num;
			}
			return flag;
		}

		// Token: 0x06001466 RID: 5222 RVA: 0x00413818 File Offset: 0x00411A18
		internal static bool HijackSendData(int whoAmI, int msgType, int remoteClient, int ignoreClient, NetworkText text, int number, float number2, float number3, float number4, int number5, int number6, int number7)
		{
			bool flag = false;
			foreach (Mod mod in ModLoader.LoadedMods)
			{
				flag |= mod.HijackSendData(whoAmI, msgType, remoteClient, ignoreClient, text, number, number2, number3, number4, number5, number6, number7);
			}
			return flag;
		}

		// Token: 0x040014B2 RID: 5298
		internal static bool downloadModsFromServers = true;

		// Token: 0x040014B3 RID: 5299
		internal static bool onlyDownloadSignedMods = false;

		// Token: 0x040014B4 RID: 5300
		internal static bool[] isModdedClient = new bool[256];

		// Token: 0x040014B5 RID: 5301
		private static Mod[] netMods;

		// Token: 0x040014B6 RID: 5302
		private static Queue<ModNet.ModHeader> downloadQueue = new Queue<ModNet.ModHeader>();

		// Token: 0x040014B7 RID: 5303
		private static ModNet.ModHeader downloadingMod;

		// Token: 0x040014B8 RID: 5304
		private static FileStream downloadingFile;

		// Token: 0x040014B9 RID: 5305
		private static long downloadingLength;

		// Token: 0x040014BA RID: 5306
		private const int CHUNK_SIZE = 16384;

		// Token: 0x020001E5 RID: 485
		private class ModHeader
		{
			// Token: 0x06001469 RID: 5225 RVA: 0x000103A0 File Offset: 0x0000E5A0
			public ModHeader(string name, Version version, byte[] hash, bool signed)
			{
				this.name = name;
				this.version = version;
				this.hash = hash;
				this.signed = signed;
				this.path = Path.Combine(ModLoader.ModPath, name + ".tmod");
			}

			// Token: 0x0600146A RID: 5226 RVA: 0x000103E0 File Offset: 0x0000E5E0
			public bool Matches(TmodFile mod)
			{
				return this.name == mod.name && this.version == mod.version && this.hash.SequenceEqual(mod.hash);
			}

			// Token: 0x0600146B RID: 5227 RVA: 0x0001041B File Offset: 0x0000E61B
			public override string ToString()
			{
				return this.name + " v" + this.version;
			}

			// Token: 0x040014BB RID: 5307
			public string name;

			// Token: 0x040014BC RID: 5308
			public Version version;

			// Token: 0x040014BD RID: 5309
			public byte[] hash;

			// Token: 0x040014BE RID: 5310
			public bool signed;

			// Token: 0x040014BF RID: 5311
			public string path;
		}
	}
}
